package com.roger.springcloudGreenwich.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.sniff.Sniffer;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.util.List;

/**
 * Created by admin on 2020/3/26.
 */
@Configuration
@Slf4j
public class HighLevelElasticSearchConfig implements FactoryBean<RestHighLevelClient>, InitializingBean, DisposableBean {
    @Value("${spring.data.elasticsearch.cluster-name}")
    private String clusterName;
    @Value("${spring.data.elasticsearch.cluster-nodes}")
    private List<String> clusterNodesList;
    private RestHighLevelClient restHighLevelClient;
    private String username = "";
    private String password = "";

    @Override
    public void destroy() throws Exception {
        try {
            log.info("Closing elasticSearch client");
            if (restHighLevelClient != null) {
                restHighLevelClient.close();
            }
        } catch (final Exception e) {
            log.error("Error closing ElasticSearch client: ", e);
        }
    }

    @Override
    public RestHighLevelClient getObject() throws Exception {
        return restHighLevelClient;
    }

    @Override
    public Class<RestHighLevelClient> getObjectType() {
        return RestHighLevelClient.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        buildClient();
    }

    protected void buildClient() {
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
        //
        String host;
        int port;
        String[] temp;

        RestClientBuilder builder = null;

		/*restClient 初始化*/
        for (String hostPort : clusterNodesList) {
            temp = hostPort.split(":");
            host = temp[0].trim();
            port = Integer.parseInt(temp[1].trim());
            builder = RestClient.builder(new HttpHost(host, port, "http"));
        }
        //
        builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                    @Override
                    public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                        return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                    }
                });

        /*1.设置请求头，避免每个请求都必须指定*/
        Header[] defaultHeaders = new Header[]{
                new BasicHeader("header", "value")
        };
        builder.setDefaultHeaders(defaultHeaders);
        /*2.设置在同一请求进行多次尝试时应该遵守的超时时间。默认值为30秒，与默认`socket`超时相同。
            如果自定义设置了`socket`超时，则应该相应地调整最大重试超时。*/

        builder.setMaxRetryTimeoutMillis(10000);
        /*3.设置每次节点发生故障时收到通知的侦听器。内部嗅探到故障时被启用。*/
        builder.setFailureListener(new RestClient.FailureListener() {
            //@Override
            public void onFailure(HttpHost host) {
                // TODO 这里是当嗅探器测出某个节点有故障时，如何提醒用户，或有问题后做其他操作。
            }
        });

        builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {

            @Override
            public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                //线程设置
                httpClientBuilder.setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(10).build());
                return httpClientBuilder;
            }
        });

        restHighLevelClient = new RestHighLevelClient(builder);
    }



}
